# !/usr/bin/env python
# -*-coding:utf-8 -*-
import json

import allure
import redis
from numba.core.compiler_machinery import pass_info
from redis.cluster import RedisCluster, ClusterNode
from public_tools.common_vars import log
from init_models import EnvInfo
from redis.cluster import RedisCluster
from typing import Union, Optional, Dict, List
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_result


class RedisClient:
    def __init__(self, rds="zone", **kwargs):
        """
        zone 为集群和哨兵并存
        :param rds: Redis 连接模式，默认为 zone
        :param kwargs: Redis 配置参数，根据不同模式传递不同的参数
        """
        from redis.sentinel import Sentinel

        # 初始化哨兵连接
        self.sentinel = Sentinel(
            sentinels=[(EnvInfo.z_rds_host_sentinel, EnvInfo.z_rds_port_sentinel)],
            password=EnvInfo.z_rds_pwd_sentinel,
            socket_timeout=5
        )

        # 获取主节点连接（用于写操作）
        self.master = self.sentinel.master_for(
            service_name='mymaster',  # 根据实际配置修改
            password=EnvInfo.z_rds_pwd_sentinel,
            decode_responses=True,
            socket_timeout=5
        )

        # 获取从节点连接（用于读操作）
        self.slave = self.sentinel.slave_for(
            service_name='mymaster',  # 根据实际配置修改
            password=EnvInfo.z_rds_pwd_sentinel,
            decode_responses=True,
            socket_timeout=5
        )

        # 默认使用主节点作为客户端
        self.client = self.master

    # 字符串操作
    def set(self, key, value, ex=None):
        """设置键值对，使用主节点"""
        return self.master.set(key, value, ex=ex)

    def get(self, key):
        """获取键值，使用从节点"""
        return self.slave.get(key)

    # 哈希表操作
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_fixed(2),
        retry=retry_if_result(lambda result: result == {})
    )
    def hget_all(self, key: str) -> Dict[str, str]:
        """获取哈希表所有字段和值"""
        try:
            result = self.slave.hgetall(key)
            log.info(f"获取哈希表 {key} 成功: {result}")
            allure.attach(
                json.dumps(result, ensure_ascii=False, indent=4),
                name="redis info logger",
                attachment_type=allure.attachment_type.TEXT
            )
            return result
        except Exception as e:
            log.error(f"获取哈希表 {key} 失败: {str(e)}")
            return {}

    def hget(self, key, field):
        """获取哈希表中指定字段的值"""
        return self.slave.hget(key, field)

    def hset(self, key, field, value):
        """设置哈希表字段的值"""
        return self.master.hset(key, field, value)

    def hmset(self, key, mapping):
        """批量设置哈希表字段的值"""
        return self.master.hmset(key, mapping)

    # 列表操作
    def lpush(self, key, *values):
        """向列表左侧添加元素"""
        return self.master.lpush(key, *values)

    def rpush(self, key, *values):
        """向列表右侧添加元素"""
        return self.master.rpush(key, *values)

    def lpop(self, key):
        """从列表左侧弹出元素"""
        return self.master.lpop(key)

    def rpop(self, key):
        """从列表右侧弹出元素"""
        return self.master.rpop(key)

    def lrange(self, key, start=0, end=-1):
        """获取列表指定范围的元素"""
        return self.slave.lrange(key, start, end)

    # 集合操作
    def sadd(self, key, *members):
        """向集合添加元素"""
        return self.master.sadd(key, *members)

    def smembers(self, key):
        """获取集合所有成员"""
        return self.slave.smembers(key)

    def srem(self, key, *members):
        """从集合移除元素"""
        return self.master.srem(key, *members)

    # 有序集合操作
    def zadd(self, key, mapping):
        """向有序集合添加元素"""
        return self.master.zadd(key, mapping)

    def zrange(self, key, start=0, end=-1, withscores=False):
        """获取有序集合指定范围的元素"""
        return self.slave.zrange(key, start, end, withscores=withscores)

    def zrange_by_score(self, key, min_score, max_score):
        """获取有序集合指定分数范围的元素"""
        return self.slave.zrangebyscore(key, min_score, max_score)

    def zrem(self, key, *members):
        """从有序集合移除元素"""
        return self.master.zrem(key, *members)

    # 键操作
    def delete(self, *keys):
        """删除键"""
        return self.master.delete(*keys)

    def exists(self, key):
        """检查键是否存在"""
        return self.slave.exists(key)

    def expire(self, key, seconds):
        """设置键的过期时间"""
        return self.master.expire(key, seconds)

    def ttl(self, key):
        """获取键的剩余过期时间"""
        return self.slave.ttl(key)

    def keys(self, pattern):
        """获取匹配模式的键"""
        return self.slave.keys(pattern)

    def scan_iter(self, match=None, count=None):
        """迭代扫描匹配的键"""
        return self.slave.scan_iter(match=match, count=count)

    # 根据键类型自动选择查询方法
    def query_by_key(self, key):
        """
        根据键的类型自动选择合适的查询方法
        :param key: Redis键
        :return: 查询结果
        """
        key_type = self.slave.type(key)

        if key_type == "string":
            return self.get(key)
        elif key_type == "hash":
            return self.hget_all(key)
        elif key_type == "list":
            return self.lrange(key)
        elif key_type == "set":
            return self.smembers(key)
        elif key_type == "zset":
            return self.zrange(key)
        else:
            return None


class RedisClusterClient:
    def __init__(self, rds="union", **kwargs):
        ""
        """
        初始化 Redis 集群连接
        :param host: 集群节点 IP
        :param port: 集群节点端口
        :param pwd: 集群访问密码（可选）
        """
        self.host = EnvInfo.z_rds_host if rds == 'zone' else EnvInfo.u_rds_host
        self.port = EnvInfo.z_rds_port if rds == 'zone' else EnvInfo.u_rds_port
        self.pwd = EnvInfo.z_rds_pwd if rds == 'zone' else EnvInfo.u_rds_pwd
        self.startup_nodes = [
            ClusterNode(host=self.host, port=self.port)
        ]
        try:
            self.client = RedisCluster(
                startup_nodes=self.startup_nodes,
                password=self.pwd,
                decode_responses=True,
                skip_full_coverage_check=True,
                ssl=False

            )
        except Exception as e:
            raise ConnectionError(f"Redis 集群连接失败: {str(e)}") from e

    def get_str(self, key: str) -> Optional[str]:
        return self.client.get(key)

    def set_str(self, key: str, value: Union[str, int], ex: int = None) -> bool:
        return self.client.set(key, value, ex=ex)
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_fixed(2),
        retry=retry_if_result(lambda result: result == {})
    )
    def hget_all(self, key: str) -> Dict[str, str]:
        try:
            result = self.client.hgetall(key)
            log.info(f"获取哈希表 {key} 成功: {result}")
            allure.attach(
                json.dumps(result, ensure_ascii=False, indent=4),
                name="redis info logger",
                attachment_type=allure.attachment_type.TEXT
            )
            return result
        except Exception as e:
            log.error(f"获取哈希表 {key} 失败: {str(e)}")
            return {}

    def hget_field(self, key: str, field: str) -> Optional[str]:
        return self.client.hget(key, field)

    def lrange(self, key: str, start: int = 0, end: int = -1) -> List[str]:
        return self.client.lrange(key, start, end)

    def smembers(self, key: str) -> List[str]:
        return self.client.smembers(key)

    def zrange_by_score(self, key: str, min_score: float, max_score: float) -> List[str]:
        return self.client.zrangebyscore(key, min_score, max_score)


if __name__ == '__main__':
    redis_cluster = RedisClusterClient()
    aa = redis_cluster.hget_all("cgconsole:{kuaishou}:session:b08127c33d464fedbb1395386118874d")
    print(type(aa))
